﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.StaticFiles;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Yz.Base;
using Yz.Core.Apis;
using Yz.Core.Extensions;

namespace Yz.FileService.Middlewares
{
    public class RemoteDownloadMiddleware : BaseUploadMiddleware, IMiddleware
    {

        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            context.Response.ContentType = "application/json; charset=utf-8";
            if (context.Request.Method.Equals(HttpMethods.Options, StringComparison.OrdinalIgnoreCase))
            {
                base.AddHttpOptionHeader(context);
            }
            else if (context.Request.Method.Equals(HttpMethods.Get, StringComparison.OrdinalIgnoreCase))
            {
                var w = int.Parse(context.Request.Query["w"].FirstOrDefault() ?? "0");//图片宽度
                var h = int.Parse(context.Request.Query["h"].FirstOrDefault() ?? "0");//图片高度
                string fileUrl = context.Request.Query["file"].FirstOrDefault() ?? "";//远程文件地址 
                if (!fileUrl.ValidFullUrl())
                {
                    await context.Response.WriteAsync(new VmReturn()
                    {
                        msg = "文件地址不正确！"
                    }.ToJson());
                    return;
                }
                var ext = Path.GetExtension(fileUrl);
                string fileId = fileUrl.ToMd5Hash16();
                var folder = Path.Combine(_uploadConfig.PhysicalPath, fileId);
                if (!Directory.Exists(folder))
                {
                    Directory.CreateDirectory(folder);
                }
                BaseApiFile fileInfo = new BaseApiFile();
                string filePath = "";
                var fileName = Directory.GetFiles(folder).Where(p => Path.GetFileName(p).Contains(fileId + ".")).FirstOrDefault();
                var imageExts = _uploadConfig.Limits.Where(p => p.Key == "image").Select(p => p.Value).FirstOrDefault().AllowExts;
                if (string.IsNullOrEmpty(fileName))//不存在
                {
                    string apiUrl = fileUrl;
                    fileInfo = RestSharpApi.DownLoadFile(apiUrl, "");
                    if (fileInfo == null || string.IsNullOrEmpty(fileInfo.ContentType) || fileInfo.FileBytes == null || fileInfo.FileBytes.Length == 0)
                    {
                        await context.Response.WriteAsync(new VmReturn()
                        {
                            msg = "文件下载失败！"
                        }.ToJson());
                        return;
                    }
                    if (!string.IsNullOrEmpty(fileInfo.ContentType))
                    {
                        ext = fileInfo.ContentType.Substring(fileInfo.ContentType.IndexOf("/")).Replace("/", ".");
                    }
                    if (!imageExts.Contains(ext))
                    {
                        await context.Response.WriteAsync(new VmReturn()
                        {
                            msg = "文件格式不支持！"
                        }.ToJson());
                        return;
                    }
                    filePath = Path.Combine(folder, fileId + ext);
                    using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                    {
                        fileStream.Write(fileInfo.FileBytes, 0, fileInfo.FileBytes.Length);
                        fileStream.Flush(true);
                    }
                    if (!File.Exists(filePath))//不存在
                    {
                        await context.Response.WriteAsync(new VmReturn()
                        {
                            msg = "文件下载失败！"
                        }.ToJson());
                        return;
                    }
                }
                else
                {
                    ext = Path.GetExtension(fileName);
                    filePath = Path.Combine(folder, fileId + ext);
                }
                if (imageExts.Contains(ext) && (w > 0 || h > 0))
                {
                    //是图片 
                    string fileNewPath = Path.Combine(folder, fileId + "_" + w + "_" + h + ext);
                    if (!File.Exists(fileNewPath))//不存在
                    {
                        using (var image = Image.FromFile(filePath))
                        {
                            using (var thumb = image.GetThumbnailImage(w, h))
                            {
                                thumb.Save(fileNewPath, ImageFormat.Jpeg);
                            }
                        }
                    }
                    filePath = fileNewPath;
                }
                var provider = new FileExtensionContentTypeProvider();
                var contentType = provider.Mappings[ext];
                int dataBufferSize = _uploadConfig.DownloadSize;   //每次分批加载的50m
                context.Response.Clear();
                context.Response.Headers.Add("Content-Disposition", "attachment; filename=" + fileId + ext);
                context.Response.ContentType = contentType;
                using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                {
                    long contentLength = stream.Length;
                    byte[] buffer;
                    long hasRead = 0;//变量hasRead用于记录已经发送了多少字节的数据到客户端浏览器
                                     //context.Response.Clear();
                                     //如果hasRead小于contentLength，说明下载文件还没读取完毕，继续循环读取下载文件的内容，并发送到客户端浏览器
                    while (hasRead < contentLength)
                    {
                        buffer = new byte[dataBufferSize];
                        int currentRead = await stream.ReadAsync(buffer, 0, dataBufferSize);//从数据流中读取bufferSize大小的内容到服务器内存中
                        await context.Response.Body.WriteAsync(buffer, 0, currentRead);//发送读取的内容数据到客户端浏览器
                        await context.Response.Body.FlushAsync(); //注意每次Write后，要及时调用Flush方法，及时释放服务器内存空间
                        hasRead += currentRead;//更新已经发送到客户端浏览器的字节数
                    }
                    return;
                }
            }
            else
            {
                await base.AddHttpNotAllowedAsync(context);
            }
        }


    }
}
